package org.databandtech.mockmq;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import org.apache.commons.compress.archivers.ArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveEntry;
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
import org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;
import org.apache.commons.compress.archivers.zip.Zip64Mode;
import org.apache.commons.compress.archivers.zip.ZipArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
import org.apache.commons.compress.archivers.zip.ZipArchiveOutputStream;
import org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream;
import org.apache.commons.compress.compressors.gzip.GzipCompressorOutputStream;
import org.apache.commons.compress.compressors.gzip.GzipParameters;
import org.apache.commons.compress.compressors.gzip.GzipUtils;
import org.apache.commons.compress.utils.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class CompressFileUtils {
	
	private static Logger logger = LoggerFactory.getLogger(CompressFileUtils.class);
    public static String CHARSET_UTF8 = "UTF-8";
	/**
	 * 解压
	 * @param zipFilePath
	 * @param saveFileDir
	 */
	public static void decompressZip(String zipFilePath,String saveFileDir) {
        if(isEndsWithZip(zipFilePath)) {
            File file = new File(zipFilePath);
            if(file.exists()) {
                InputStream is = null;
                //can read Zip archives
                ZipArchiveInputStream zais = null;
                try {
                    is = new FileInputStream(file);
                    zais = new ZipArchiveInputStream(is);
                    ArchiveEntry  archiveEntry = null;
                    //把zip包中的每个文件读取出来
                    //然后把文件写到指定的文件夹
                    while((archiveEntry = zais.getNextEntry()) != null) {
                        //获取文件名
                        String entryFileName = archiveEntry.getName();
                        //构造解压出来的文件存放路径
                        String entryFilePath = saveFileDir + entryFileName;
                        byte[] content = new byte[(int) archiveEntry.getSize()];
                        zais.read(content);
                        OutputStream os = null;
                        try {
                            //把解压出来的文件写到指定路径
                            File entryFile = new File(entryFilePath);
                            os = new BufferedOutputStream(new FileOutputStream(entryFile));
                            os.write(content);
                        }catch(IOException e) {
                            throw new IOException(e);
                        }finally {
                            if(os != null) {
                                os.flush();
                                os.close();
                            }
                        }
                         
                    }
                }catch(Exception e) {
                    throw new RuntimeException(e);
                }finally {
                        try {
                            if(zais != null) {
                                zais.close();
                            }
                            if(is != null) {
                                is.close();
                            }
                        } catch (IOException e) {
                            throw new RuntimeException(e);
                        }
                }
            }
        }
    }
	
	/**
	 * 压缩文件
	 * @param files
	 * @param zipFilePath
	 */
	public static void compressFiles2Zip(File[] files,String zipFilePath) {
        if(files != null && files.length >0) {
            if(isEndsWithZip(zipFilePath)) {
                ZipArchiveOutputStream zaos = null;
                try {
                    File zipFile = new File(zipFilePath);
                    zaos = new ZipArchiveOutputStream(zipFile);
                    //Use Zip64 extensions for all entries where they are required
                    zaos.setUseZip64(Zip64Mode.AsNeeded);
                     
                    //将每个文件用ZipArchiveEntry封装
                    //再用ZipArchiveOutputStream写到压缩文件中
                    for(File file : files) {
                        if(file != null) {
                            ZipArchiveEntry zipArchiveEntry  = new ZipArchiveEntry(file,file.getName());
                            zaos.putArchiveEntry(zipArchiveEntry);
                            InputStream is = null;
                            try {
                                is = new BufferedInputStream(new FileInputStream(file));
                                byte[] buffer = new byte[1024 * 5]; 
                                int len = -1;
                                while((len = is.read(buffer)) != -1) {
                                    //把缓冲区的字节写入到ZipArchiveEntry
                                    zaos.write(buffer, 0, len);
                                }
                                //Writes all necessary data for this entry.
                                zaos.closeArchiveEntry(); 
                            }catch(Exception e) {
                                throw new RuntimeException(e);
                            }finally {
                                if(is != null)
                                    is.close();
                            }
                             
                        }
                    }
                    zaos.finish();
                }catch(Exception e){
                    throw new RuntimeException(e);
                }finally {
                        try {
                            if(zaos != null) {
                                zaos.close();
                            }
                        } catch (IOException e) {
                            throw new RuntimeException(e);
                        }
                }
                 
            }
             
        }
         
    }
	
	public static boolean isEndsWithZip(String fileName) {
        boolean flag = false;
        if(fileName != null && !"".equals(fileName.trim())) {
            if(fileName.endsWith(".ZIP")||fileName.endsWith(".zip")){
                flag = true;
            }
        }
        return flag;
    }
	
	public static boolean isEndsWithGZip(String fileName) {
        boolean flag = false;
        if(fileName != null && !"".equals(fileName.trim())) {
            if(fileName.endsWith(".GZ")||fileName.endsWith(".gz")){
                flag = true;
            }
        }
        return flag;
    }
	
	
	public static boolean compressByTar(String sourceFolderPath, String targetTarFilePath) throws Exception {
        // 变量定义.
        File sourceFolderFile = null;
        FileOutputStream targetTarFos = null;
        TarArchiveOutputStream targetTartTaos = null;
        TarArchiveEntry targetTarTae = null;

        try {
            // 压缩变量初始化.
            sourceFolderFile = new File(sourceFolderPath);
            targetTarFos = new FileOutputStream(new File(targetTarFilePath));
            targetTartTaos = new TarArchiveOutputStream(targetTarFos);
            // 将文件添加到ZIP条目中.
            for (File file : sourceFolderFile.listFiles()) {
                try (FileInputStream fis = new FileInputStream(file);
                        BufferedInputStream bis = new BufferedInputStream(fis);) {
                    targetTarTae = new TarArchiveEntry(file);
                    targetTarTae.setName(file.getName());
                    targetTartTaos.putArchiveEntry(targetTarTae);
                    targetTartTaos.write(IOUtils.toByteArray(bis));
                    targetTartTaos.closeArchiveEntry();
                }
            }
        } catch (Exception ex) {
            logger.info("GZipDiskUtil.compressByTar.", ex);
            return false;
        } finally {
            if (targetTartTaos != null)
                targetTartTaos.close();
            if (targetTarFos != null)
                targetTarFos.close();

        }
        return true;
    }

    /**
     * 使用TAR算法进行解压.
     * @param sourceTarPath 待解压文件路径.
     * @param targetFolderPath 解压后文件夹目录.
     * @return 解压是否成功.
     * @throws Exception 解压过程中可能发生的异常.
     */
    public static boolean decompressByTar(String sourceTarPath, String targetFolderPath) throws Exception {
        // 变量定义.
        FileInputStream sourceTarFis = null;
        TarArchiveInputStream sourceTarTais = null;
        TarArchiveEntry sourceTarTae = null;
        File singleEntryFile = null;

        try {
            // 解压定义初始化.
            sourceTarFis = new FileInputStream(new File(sourceTarPath));
            sourceTarTais = new TarArchiveInputStream(sourceTarFis);
            // 条目解压缩至指定文件夹目录下.
            while ((sourceTarTae = sourceTarTais.getNextTarEntry()) != null) {
                singleEntryFile = new File(targetFolderPath + File.separator + sourceTarTae.getName());
                try (FileOutputStream fos = new FileOutputStream(singleEntryFile);
                        BufferedOutputStream bos = new BufferedOutputStream(fos);) {
                    bos.write(IOUtils.toByteArray(sourceTarTais));
                }
            }
        } catch (Exception ex) {
            logger.info("GZipDiskUtil.decompressByTar.", ex);
            return false;
        } finally {
            if (sourceTarTais != null)
                sourceTarTais.close();
            if (sourceTarFis != null)
                sourceTarFis.close();
        }
        return true;
    }

    /**
     * 使用GZIP算法进行压缩.
     * @param sourceFilePath 待进行压缩的文件路径.
     * @param targetGZipFilePath 压缩后的GZIP文件存储目录.
     * @return 压缩是否成功.
     * @throws Exception 压缩过程中可能发生的异常.
     */
    public static boolean compressByGZip(String sourceFilePath, String targetGZipFilePath) throws IOException {
        // 变量定义.
        FileInputStream sourceFileFis = null;
        BufferedInputStream sourceFileBis = null;
        FileOutputStream targetGZipFileFos = null;
        BufferedOutputStream targetGZipFileBos = null;
        GzipCompressorOutputStream targetGZipFileGcos = null;

        try {
            // 压缩变量初始化.
            sourceFileFis = new FileInputStream(new File(sourceFilePath));
            sourceFileBis = new BufferedInputStream(sourceFileFis);
            targetGZipFileFos = new FileOutputStream(targetGZipFilePath);
            targetGZipFileBos = new BufferedOutputStream(targetGZipFileFos);
            targetGZipFileGcos = new GzipCompressorOutputStream(targetGZipFileBos);
            // 采用commons-compress提供的方式进行压缩.
            targetGZipFileGcos.write(IOUtils.toByteArray(sourceFileBis));
        } catch (Exception ex) {
            logger.info("GZipDiskUtil.compressByGZip.", ex);
            return false;
        } finally {
            if (targetGZipFileGcos != null)
                targetGZipFileGcos.close();
            if (targetGZipFileBos != null)
                targetGZipFileBos.close();
            if (targetGZipFileFos != null)
                targetGZipFileFos.close();
            if (sourceFileBis != null)
                sourceFileBis.close();
            if (sourceFileFis != null)
                sourceFileFis.close();
        }
        return true;
    }

    /**
     * 使用GZIP算法进行解压.
     * @param sourceGZipFilePath 待解压文件路径.
     * @param targetFilePath 解压后文件路径.
     * @return 解压是否成功.
     * @throws @throws Exception 解压过程中可能发生的异常.
     */
    public static boolean decompressByGZip(String sourceGZipFilePath, String targetFilePath) throws IOException {
        // 变量定义.
        FileInputStream sourceGZipFileFis = null;
        BufferedInputStream sourceGZipFileBis = null;
        FileOutputStream targetFileFos = null;
        GzipCompressorInputStream sourceGZipFileGcis = null;

        try {
            // 解压变量初始化.
        	File infile = new File(sourceGZipFilePath);
        	String outfilename = infile.getName().substring(0, infile.getName().lastIndexOf(".gz"));
            sourceGZipFileFis = new FileInputStream(infile);
            
            sourceGZipFileBis = new BufferedInputStream(sourceGZipFileFis);
            sourceGZipFileGcis = new GzipCompressorInputStream(sourceGZipFileBis);
            targetFileFos = new FileOutputStream(new File(targetFilePath + outfilename));
            // 采用commons-compress提供的方式进行解压.
            targetFileFos.write(IOUtils.toByteArray(sourceGZipFileGcis));
        } catch (Exception ex) {
            logger.info("GZipDiskUtil.decompressByGZip.", ex);
            return false;
        } finally {
            if (sourceGZipFileGcis != null)
                sourceGZipFileGcis.close();
            if (sourceGZipFileBis != null)
                sourceGZipFileBis.close();
            if (sourceGZipFileFis != null)
                sourceGZipFileFis.close();
            if (targetFileFos != null)
                targetFileFos.close();
        }
        return true;
    }


}
